import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { CreateCommentDto } from './dto/create-comment.dto';
import { UpdateCommentDto } from './dto/update-comment.dto';
import { InjectRepository } from '@nestjs/typeorm';
import { Comment, StatusComment } from './entities//comment.entity';
import { Repository } from 'typeorm';
import { Posts } from '../posts/entities/post.entity';
import { HttpService } from '@nestjs/axios';
import { ConfigService } from '@nestjs/config';
import { JwtService } from '@nestjs/jwt';
import { filterXSS } from 'xss';
import { ExternalService } from '../external/external.service';
import { SmtpService } from '../smtp/smtp.service';
import { UserRole, Users } from '../users/entities/user.entity';
import { QueryCommentDto } from './dto/query-comment.dto';
@Injectable()
export class CommentsService {
  constructor(
    @InjectRepository(Comment)
    private readonly commentRepository: Repository<Comment>,
    @InjectRepository(Posts)
    private postsRepository: Repository<Posts>,
    private configService: ConfigService,
    private httpService: HttpService,
    private smtpService: SmtpService,
    private jwtService: JwtService,
    private externalService: ExternalService,
  ) {}
  async create(ip, ua, token, createCommentDto: CreateCommentDto) {
    createCommentDto.ip = ip;
    createCommentDto.ua = ua;
    createCommentDto.isAdmin = false; // 统一false，防止前端直接传值
    if (token) {
      const { role, nickname } = this.jwtService.decode(token) as Users;
      createCommentDto.isAdmin = role !== UserRole.visitor;
      createCommentDto.name = nickname;
    }
    // xss过滤
    createCommentDto.content = filterXSS(createCommentDto.content);
    createCommentDto.name = filterXSS(createCommentDto.name);
    // 判断评论所属资源是否开启评论
    const exitsContent = await this.postsRepository.findOne({
      where: { id: createCommentDto.resourceId },
    });
    if (exitsContent && !exitsContent.isCommentOpen) {
      throw new HttpException('非法评论', HttpStatus.FORBIDDEN);
    }

    // 文本检测
    const { result } = await this.externalService.checkText(
      createCommentDto.content,
    );
    createCommentDto.status = result?.suggestion;
    createCommentDto.suggestion = JSON.stringify(result?.scenes);

    let parentComment = null;
    if (createCommentDto.parent) {
      parentComment = await this.commentRepository.findOne({
        where: { id: createCommentDto.parent },
      });
    }
    // 保存到数据库
    const createComment = this.commentRepository.create({
      ...createCommentDto,
      parent: parentComment,
    });
    const exitsComment = await this.commentRepository.save(createComment);

    // 邮件后面发
    if (StatusComment.Pass !== exitsComment.status) {
      throw new HttpException(
        '评论包含敏感信息，已屏蔽！',
        HttpStatus.PRECONDITION_FAILED,
      );
    }
    const SITE_NAME = this.configService.get('SITE_NAME');
    const SITE_URL = this.configService.get('SITE_URL');
    const SITE_EMAIL = this.configService.get('SITE_EMAIL');
    const SMTP_FROM = this.configService.get('SMTP_FROM');
    // 评论通过
    if (exitsComment.status === StatusComment.Pass) {
      const mailOptions = {
        from: SMTP_FROM,
        to: exitsComment.replyEmail,
        subject: `「 ${SITE_NAME} 」回复通知`,
        template: 'replyTemp',
        context: {
          // Data to be sent to template engine.
          text: exitsComment.content,
          siteName: SITE_NAME,
          siteUrl: SITE_URL,
          name: exitsComment.name,
          replyName: exitsComment.replyName,
          reviewUrl: `${SITE_URL}/post/${exitsComment.id}`,
        },
        //  多余字段。给smtp存储的
        text: exitsComment.content,
        fromEmail: exitsComment.email || SMTP_FROM, // 这里发送人邮箱
        toEmail: exitsComment.replyEmail, // 这里收件人的邮箱
      };
      // 回复他人，发送邮件通知
      if (exitsComment.parent) {
        this.smtpService.create(mailOptions).catch(() => {
          console.log('评论成功，发送邮件失败');
        });
      }
      // 通知站长
      if (!exitsComment.isAdmin) {
        const siteMailOption = Object.assign(mailOptions, {
          to: SITE_EMAIL,
          subject: `「 ${SITE_NAME} 」评论通知`,
          template: 'noticeTemp',
          toEmail: SITE_EMAIL, // 配置的站长邮箱
        });
        this.smtpService.create(siteMailOption).catch(() => {
          console.log('通知站长，评论成功，发送邮件失败');
        });
      }
    }
    return exitsComment;
  }

  async findAll(query: QueryCommentDto) {
    const { pageNum = 1, pageSize = 10, status, sortBy, ...otherQuery } = query;
    const commentQuery = await this.commentRepository
      .createQueryBuilder('comment')
      .take(pageSize)
      .skip((pageNum - 1) * pageSize);

    if (status) {
      commentQuery.andWhere('comment.status=:status', { status });
    }

    if (sortBy) {
      const sortByObject = JSON.parse(sortBy);
      Object.keys(sortByObject).forEach((key) =>
        commentQuery.orderBy(`comment.${key}`, sortByObject[key]),
      );
    } else {
      commentQuery.orderBy('comment.createTime', 'DESC');
    }
    if (otherQuery) {
      Object.keys(otherQuery).forEach((q) =>
        commentQuery.andWhere(`comment.${q} LIKE :${q}`, {
          [`${q}`]: `%${otherQuery[q]}%`,
        }),
      );
    }

    const count = await commentQuery.getCount();
    const list = await commentQuery.getMany();
    return {
      count,
      list,
    };
  }

  findOne(id: number) {
    return this.commentRepository.findOne({ where: { id: id } });
  }

  async update(id: number, updateCommentDto: UpdateCommentDto) {
    const exitsComment = await this.commentRepository.findOne({
      where: { id: id },
    });
    if (!exitsComment) {
      throw new HttpException(`不存在id为${id}的评论`, HttpStatus.BAD_REQUEST);
    }
    const updateComment = this.commentRepository.merge(
      exitsComment,
      updateCommentDto,
    );

    // todo 更新评论，发送通知
    if (updateComment.status === StatusComment.Pass && updateComment.parent) {
    }
    return this.commentRepository.save(updateComment);
  }

  async remove(id: number) {
    const qb = this.commentRepository
      .createQueryBuilder('comment')
      .innerJoin('comment.parent', 'parent', 'parent.id = :id', { id });
    const children = await qb.getOne();
    if (children) {
      throw new HttpException(
        `id为${id}的评论下存在子评论，不允许删除`,
        HttpStatus.BAD_REQUEST,
      );
    }
    return this.commentRepository.delete(id);
  }

  async findByResourceId(resourceId: string) {
    const qb = this.commentRepository
      .createQueryBuilder('comment')
      .leftJoinAndSelect('comment.children', 'children')
      .andWhere('comment.resourceId = :resourceId', { resourceId: resourceId })
      .andWhere(`comment.parentId is NULL`)
      .orderBy('comment.updateTime', 'DESC');

    const comments = await qb.getMany();
    return comments;
  }
}
